package com.iflytek.sbd.aspect;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONArray;
import com.iflytek.sbd.utils.ParameterUtils;
import com.iflytek.sbd.utils.RedisUtils;
import com.iflytek.sbd.vo.InfoVO;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.*;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;

import javax.servlet.http.HttpServletRequest;
import java.util.Arrays;
import java.util.List;

/**
 * @program: sbd
 * @description:
 * @author: 陈英俊
 * @create: 2021-12-29 11:19
 */
@Aspect
@Component
public class ControllerAspect {



    @Autowired
    private RedisUtils redisUtils;



    /**     * @Pointcut: 是针对方法来进行配置的, 也可以使用包进行配置
     * @Within: 可以
     */


    @Pointcut("execution(* com.iflytek.sbd.controller.*.*(..)))")
    public void controllerAspect() {
    }


    /**
     * 环绕增强: 在目标方法调用之前或之后执行自定义的方法
     * 发生了异常,没进去这里
     *
     * @param joinPoint
     * @return
     * @throws Throwable
     */
    // @Around("controllerAspect()")
    public Object doAround(ProceedingJoinPoint joinPoint) throws Throwable {
        // 得到请求的参数 可以对参数进行修改
        Object[] args = joinPoint.getArgs();
        args[0] = "23";
        // 此处是重载的方法,对参数进行修改的话,可以调用带args的方法,不然即使在这里修改了参数,控制层接收到的方法参数是没有改变的
//        Object result =    joinPoint.proceed();
        // 此方法去执行实际方法,可以得到方法的返回值
        Object result = joinPoint.proceed(args);
        Object target = joinPoint.getTarget();// 我们自己写的控制类
        Object aThis = joinPoint.getThis();//CGLB动态代理类
        return result;
    }


    /**
     * 前置增强：在目标方法之前调用通知
     * 发生了异常没进入这里
     *
     * @param joinPoint
     */
   //  @Before("controllerAspect()")
    public void doBefore(JoinPoint joinPoint) {
        ServletRequestAttributes attributes = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes();
//        if (attributes != null) {
//            HttpServletRequest request = attributes.getRequest();
//            System.out.println("请求全部路径 : " + request.getRequestURL().toString());
//            System.out.println("请求方式 : " + request.getMethod());
//            System.out.println("IP地址 : " + request.getRemoteAddr());
//            System.out.println("请求的方法全限定名称 : " + joinPoint.getSignature().getDeclaringTypeName() + "." + joinPoint.getSignature().getName());
//            System.out.println("请求参数 : " + Arrays.toString(joinPoint.getArgs()));
//        }

         List<Object> objects = Arrays.asList(joinPoint.getArgs());
         InfoVO infoVO = (InfoVO) objects.get(0);
         String md5 = ParameterUtils.paramMD5(JSON.toJSONString(infoVO), "requstTime");
         redisUtils.limitMethodRepeatedConsumption(md5,"chenliang","methedName",20000);

     }


    /**
     * 返回通知:　目标方法执行成功之后调用通知
     * 异常进入不了
     *
     * @param ret
     */
    //  @AfterReturning(returning = "ret", pointcut = "controllerAspect()")
    public void doAfterReturning(Object ret) {
        System.out.println(ret);
    }


    /**
     * 异常通知: 目标方法抛出异常才会进入
     * 异常才会进入
     *
     * @param ex
     */
    //  @AfterThrowing(throwing = "ex", pointcut = "controllerAspect()")
    public void doAfterThrowing(Exception ex) {
        System.out.println(ex);
    }


    /**
     * 后置通知: 在目标方法方法完成之后调用, 不论是否异常,都会执行
     *
     * @param joinPoint
     */
    //@After("controllerAspect()")
    public void doAfter(JoinPoint joinPoint) {
        System.out.println("进入@After切面");
    }


}